package schema

import (
	"strings"

	"github.com/samber/lo"
)

type GenerateFunc func(c *TableColumn, err error) error

// GenerateRule
// 根据字段名列表生成字段配置列表，
// 字段名匹配配置方式有三种：全匹配，头匹配，尾匹配；
// 按照顺序进行匹配，匹配到一个则使用该匹配方式对应的规则进行生成配置，
// 每个匹配方式都有多个规则，且在策略初始化的时候就进行设
type GenerateRule interface {
	ConfigGenerate(c *TableColumn) error
}

type DefaultGenerateRule struct {
	Payload string
	Fn      GenerateFunc
}

func (r DefaultGenerateRule) ConfigGenerate(c *TableColumn) error {
	var err error
	return r.Fn(c, err)
}

// FieldMatchStrategy 字段匹配策略
type FieldMatchStrategy interface {
	//	Match 该列是否使用当前策略
	PayloadsMatch(c *TableColumn) bool
	// ColumnMatch 字段是否匹配单个关键字
	ColumnMatch(c *TableColumn, payload string) bool
	// Upgrade 更新列配置
	Upgrade(c *TableColumn) error
}

type DefaultMatchNode struct {
	activeIndex       *int
	Rules             []*DefaultGenerateRule
	NextHandler       MatchHandler
	NextMatchStrategy FieldMatchStrategy
}

func (n *DefaultMatchNode) PayloadsMatch(c *TableColumn) bool {
	payloads := lo.Map(n.Rules, func(r *DefaultGenerateRule, _ int) string {
		return r.Payload
	})
	_, index, ok := lo.FindIndexOf(payloads, func(p string) bool {
		return n.ColumnMatch(c, p)
	})
	if ok {
		n.activeIndex = &index
	}
	return ok
}

func (n *DefaultMatchNode) Upgrade(c *TableColumn) error {
	return n.Rules[*n.activeIndex].ConfigGenerate(c)
}

func (n *DefaultMatchNode) ColumnMatch(c *TableColumn, payload string) bool {
	return true
}

// FullMatchStrategy
// 全匹配策略
type FullMatchStrategy struct {
	DefaultMatchNode
}

func (s *FullMatchStrategy) ColumnMatch(c *TableColumn, p string) bool {
	return c.ColumnName == p
}

type PrefixMatchStrategy struct {
	DefaultMatchNode
}

func (s *PrefixMatchStrategy) ColumnMatch(c *TableColumn, p string) bool {
	return strings.HasPrefix(c.ColumnName, p)
}

type SuffixMatchStrategy struct {
	DefaultMatchNode
}

func (s *SuffixMatchStrategy) ColumnMatch(c *TableColumn, p string) bool {
	return strings.HasSuffix(c.ColumnName, p)
}

type MatchHandler interface {
	Handler(c TableColumn, dest *[]TableColumn)
	SetNext(handler MatchHandler, strategy FieldMatchStrategy)
}

func (n *DefaultMatchNode) Handler(c TableColumn, dest *[]TableColumn) {
	if n.PayloadsMatch(&c) {
		err := n.Upgrade(&c)
		if err != nil {
			println(err)
		}
		*dest = append(*dest, c)
	}
	if n.NextHandler != nil {
		nextHandler := n.NextHandler
		nextHandler.Handler(c, dest)
	}
}

func (n *DefaultMatchNode) SetNext(handler MatchHandler, strategy FieldMatchStrategy) {
	n.NextHandler = handler
	n.NextMatchStrategy = strategy
}

type FullMatchHandler struct {
	DefaultMatchNode
}

type PrefixMatchHandler struct {
	DefaultMatchNode
}

type SuffixMatchHandler struct {
	DefaultMatchNode
}
